﻿using System;
using System.IO;

namespace NFinal
{
    /// <summary>
    /// 工具类，字符串处理
    /// </summary>
    public static class Utility
    {
        private static string rootDir=null;
        /// <summary>
        /// 返回服务器路径
        /// </summary>
        /// <param name="path">相对路径</param>
        /// <returns></returns>
        public static string MapPath(string path)
        {
            if (rootDir == null)
            {
                rootDir = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
            }
            return System.IO.Path.Combine(rootDir, path.TrimStart('/').Replace('/', Path.DirectorySeparatorChar));
        }
        private static System.Text.Encoding encoding = System.Text.Encoding.UTF8;
        /// <summary>
        /// 十六进制字符转整数
        /// </summary>
        /// <param name="h">十六进制字符</param>
        /// <returns>整数</returns>
        private static int HexToInt(char h)
        {
            return (h >= '0' && h <= '9') ? h - '0' :
            (h >= 'a' && h <= 'f') ? h - 'a' + 10 :
            (h >= 'A' && h <= 'F') ? h - 'A' + 10 :
            -1;
        }
        /// <summary>
        /// 整数转十六进制字符
        /// </summary>
        /// <param name="n">整数</param>
        /// <returns>十六进制字符</returns>
        private static char IntToHex(int n)
        {

            if (n <= 9)
                return (char)(n + (int)'0');
            else
                return (char)(n - 10 + (int)'a');
        }

        // Set of safe chars, from RFC 1738.4 minus '+'
        private static bool IsUrlSafeChar(char ch)
        {
            if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
                return true;

            switch (ch)
            {
                case '-':
                case '_':
                case '.':
                case '!':
                case '*':
                case '(':
                case ')':
                    return true;
            }

            return false;
        }

        //  Helper to encode spaces only
        private static String UrlEncodeSpaces(string str)
        {
            if (str != null && str.IndexOf(' ') >= 0)
                str = str.Replace(" ", "%20");
            return str;
        }
        private static bool ValidateParameters(byte[] bytes, int offset, int count)
        {
            if (bytes == null && count == 0)
                return false;
            if (bytes == null)
            {
                throw new ArgumentNullException("bytes");
            }
            if (offset < 0 || offset > bytes.Length)
            {
                throw new ArgumentOutOfRangeException("offset");
            }
            if (count < 0 || offset + count > bytes.Length)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            return true;
        }
        private static byte[] UrlEncode(byte[] bytes, int offset, int count)
        {
            if (!ValidateParameters(bytes, offset, count))
            {
                return null;
            }

            int cSpaces = 0;
            int cUnsafe = 0;

            // count them first
            for (int i = 0; i < count; i++)
            {
                char ch = (char)bytes[offset + i];

                if (ch == ' ')
                    cSpaces++;
                else if (!IsUrlSafeChar(ch))
                    cUnsafe++;
            }

            // nothing to expand?
            if (cSpaces == 0 && cUnsafe == 0)
                return bytes;

            // expand not 'safe' characters into %XX, spaces to +s
            byte[] expandedBytes = new byte[count + cUnsafe * 2];
            int pos = 0;

            for (int i = 0; i < count; i++)
            {
                byte b = bytes[offset + i];
                char ch = (char)b;

                if (IsUrlSafeChar(ch))
                {
                    expandedBytes[pos++] = b;
                }
                else if (ch == ' ')
                {
                    expandedBytes[pos++] = (byte)'+';
                }
                else {
                    expandedBytes[pos++] = (byte)'%';
                    expandedBytes[pos++] = (byte)IntToHex((b >> 4) & 0xf);
                    expandedBytes[pos++] = (byte)IntToHex(b & 0x0f);
                }
            }

            return expandedBytes;
        }
        private static byte[] UrlDecode(byte[] bytes, int offset, int count)
        {
            if (!ValidateParameters(bytes, offset, count))
            {
                return null;
            }

            int decodedBytesCount = 0;
            byte[] decodedBytes = new byte[count];

            for (int i = 0; i < count; i++)
            {
                int pos = offset + i;
                byte b = bytes[pos];

                if (b == '+')
                {
                    b = (byte)' ';
                }
                else if (b == '%' && i < count - 2)
                {
                    int h1 = HexToInt((char)bytes[pos + 1]);
                    int h2 = HexToInt((char)bytes[pos + 2]);

                    if (h1 >= 0 && h2 >= 0)
                    {     // valid 2 hex chars
                        b = (byte)((h1 << 4) | h2);
                        i += 2;
                    }
                }

                decodedBytes[decodedBytesCount++] = b;
            }

            if (decodedBytesCount < decodedBytes.Length)
            {
                byte[] newDecodedBytes = new byte[decodedBytesCount];
                Array.Copy(decodedBytes, newDecodedBytes, decodedBytesCount);
                decodedBytes = newDecodedBytes;
            }

            return decodedBytes;
        }
        /// <summary>
        /// url编码
        /// </summary>
        /// <param name="url">原始url</param>
        /// <returns>编码后的url</returns>
        public static string UrlEncode(string url)
        {
            byte[] buffer = encoding.GetBytes(url);
            byte[] result= UrlEncode(buffer, 0, buffer.Length);
            return encoding.GetString(result);
        }
        /// <summary>
        /// url解码
        /// </summary>
        /// <param name="url">编码后的url</param>
        /// <returns>原始url</returns>
        public static string UrlDecode(string url)
        {
            byte[] buffer = encoding.GetBytes(url);
            byte[] result = UrlDecode(buffer, 0, buffer.Length);
            return encoding.GetString(result);
        }
        /// <summary>
        /// html编码
        /// </summary>
        /// <param name="html">原始的html</param>
        /// <returns>编码后的html</returns>
        public static string HtmlEncode(string html)
        {
            return System.Net.WebUtility.HtmlEncode(html);
        }
        /// <summary>
        /// html解码
        /// </summary>
        /// <param name="html">编码后的html</param>
        /// <returns>原始的html</returns>
        public static string HtmlDecode(string html)
        {
            return System.Net.WebUtility.HtmlDecode(html);
        }
        /// <summary>
        /// 把字符串转换为代码中的字符串格式
        /// </summary>
        /// <param name="bytes">字节流</param>
        /// <param name="offset">开始位置</param>
        /// <param name="count">字节数</param>
        /// <returns>代码中的字符串</returns>
        public static byte[] GetCSharpString(byte[] bytes, int offset, int count)
        {
            if (!ValidateParameters(bytes, offset, count))
            {
                return null;
            }
            int cWrapped = 0;
            // count them first
            for (int i = 0; i < count; i++)
            {
                char ch = (char)bytes[offset + i];
                switch (ch)
                {
                    case '\'': cWrapped++; break;
                    case '\"': cWrapped++; break;
                    case '\\': cWrapped++; break;
                    case '\0': cWrapped++; break;
                    case '\a': cWrapped++; break;
                    case '\b': cWrapped++; break;
                    case '\f': cWrapped++; break;
                    case '\n': cWrapped++; break;
                    case '\r': cWrapped++; break;
                    case '\t': cWrapped++; break;
                    case '\v': cWrapped++; break;
                }
            }
            if (cWrapped == 0)
            {
                return bytes;
            }
            byte[] expandedBytes = new byte[count + cWrapped + 2];
            int pos = 0;
            expandedBytes[pos++] = (byte)'\"';
            for (int i = 0; i < count; i++)
            {
                byte b = bytes[offset + i];
                char ch = (char)b;

                switch (ch)
                {
                    case '\'':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++]=(byte)'\''; break;
                    case '\"':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'\"'; break;
                    case '\\':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'\\'; break;
                    case '\0':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'0'; break;
                    case '\a':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'a'; break;
                    case '\b':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'b'; break;
                    case '\f':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'f'; break;
                    case '\n':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'n'; break;
                    case '\r':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'r'; break;
                    case '\t':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'t'; break;
                    case '\v':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'v'; break;
                    default:
                        expandedBytes[pos++] = (byte)ch; break;
                }
            }
            expandedBytes[pos++] = (byte)'\"';
            return expandedBytes;
        }
        /// <summary>
        /// 把字符串转换为代码中的字符串格式
        /// </summary>
        /// <param name="text">字符串</param>
        /// <returns>代码中的字符串</returns>
        public static string GetCSharpString(string text)
        {
            byte[] buffer = encoding.GetBytes(text);
            byte[] result = GetCSharpString(buffer, 0, buffer.Length);
            return encoding.GetString(result);
        }
        /// <summary>
        /// 把字符串转换为json中的字符串格式
        /// </summary>
        /// <param name="bytes">字节流</param>
        /// <param name="offset">开始位置</param>
        /// <param name="count">字节数</param>
        /// <returns></returns>
        public static byte[] GetJsonString(byte[] bytes, int offset, int count)
        {
            if (!ValidateParameters(bytes, offset, count))
            {
                return null;
            }
            int cWrapped = 0;
            // count them first
            for (int i = 0; i < count; i++)
            {
                char ch = (char)bytes[offset + i];
                switch (ch)
                {
                    case '\"': cWrapped++; break;
                    case '\\': cWrapped++; break;
                    case '/': cWrapped++; break;
                    case '\b': cWrapped++; break;
                    case '\f': cWrapped++; break;
                    case '\n': cWrapped++; break;
                    case '\r': cWrapped++; break;
                    case '\t': cWrapped++; break;
                }
            }
            if (cWrapped == 0)
            {
                return bytes;
            }
            byte[] expandedBytes = new byte[count + cWrapped+2];
            int pos = 0;
            expandedBytes[pos++] = (byte)'\"';
            for (int i = 0; i < count; i++)
            {
                byte b = bytes[offset + i];
                char ch = (char)b;

                switch (ch)
                {
                    case '\"':
                        expandedBytes[pos++]=(byte)'\\';
                        expandedBytes[pos++] = (byte)'\"'; break;
                    case '\\':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'\\'; break;
                    case '/':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'/'; break;
                    case '\b':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'b'; break;
                    case '\f':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'f'; break;
                    case '\n':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'n'; break;
                    case '\r':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'r'; break;
                    case '\t':
                        expandedBytes[pos++] = (byte)'\\';
                        expandedBytes[pos++] = (byte)'t'; break;
                    default:
                        expandedBytes[pos++] = (byte)ch; break;
                }
            }
            expandedBytes[pos++] = (byte)'\"';
            return expandedBytes;
        }
        /// <summary>
        /// 把字符串转换为json中的字符串格式
        /// </summary>
        /// <param name="text">字符串</param>
        /// <returns>json中的字符串格式</returns>
        public static string GetJsonString(string text)
        {
            if (text == null)
            {
                return "null";
            }
            else if (text == string.Empty)
            {
                return "\"\"";
            }
            byte[] buffer = encoding.GetBytes(text);
            byte[] result = GetJsonString(buffer, 0, buffer.Length);
            return encoding.GetString(result);
        }
    }
}
